const TimeSpan_ymdhms_regex =r"([+,-]?)P(\d+)Y(\d+)M(\d+)D(\d+)H(\d+)M([\d,\.]+)S"
const TimeSpan_ymd_regex =r"([+,-]?)P(\d+)Y(\d+)M(\d+)D"
const TimeSpan_hms_regex =r"([+,-]?)P(\d+)H(\d+)M([\d,\.]+)S"
const TimeSpan_ymdhms_regex2 =r"([+,-]?)(\d+)ʸ(\d+)ᵐ(\d+)ᵈ(\d+)ʰ(\d+)ᵐ([\d,\.]+)ˢ"
const TimeSpan_ymd_regex2 =r"([+,-]?)(\d+)ʸ(\d+)ᵐ(\d+)ᵈ"
const TimeSpan_hms_regex2 =r"([+,-]?)(\d+)ʰ(\d+)ᵐ([\d,\.]+)ˢ"

function Base.parse(::Type{TimeSpan}, str::T) where T<:AbstractString
    (str[1] == 'P' || str[1] == '-' || str[1] == '+') ||
        throw(ErrorException("\"$str\" is not a valid TimeSpan"))
	if contains(str[nextind(str,1):nextind(str,length(str)-1)], "+P")
		monthspart, nanospart = split_string(str, "+")
		nanospart = string("P", nanospart)
		parse_hms(TimeSpan, nanospart) + NanoTimes.parse_ymd(TimeSpan, monthspart)
	elseif contains(str[nextind(str,1):nextind(str,length(str)-1)], "-P")
		monthspart, nanospart = NanoTimes.split_string(str, "-P")
		nanospart = string("-P", nanospart)
		parse_hms(TimeSpan, nanospart) + parse_ymd(TimeSpan, monthspart)
	elseif str[end] == 'S' || str[end] == 'ˢ'
		if contains(str,"D") || contains(str, "ᵈ")
		   NanoTimes.parse_ymdhms(TimeSpan, str)
		else
		   NanoTimes.parse_hms(TimeSpan, str)
		end
	elseif str[end] == 'D' || str[end] == 'ᵈ'
		NanoTimes.parse_ymd(TimeSpan, str)
	else
		throw(ErrorException("\"$str\" is not a valid TimeSpan"))
	end
end

function parse_ymdhms(::Type{TimeSpan}, str::String)
    matched = match(TimeSpan_ymdhms_regex, str)
    if matched == nothing
        matched = match(TimeSpan_ymdhms_regex2, str)
    end
    matched == nothing && throw(ErrorException("Unable to parse $(str) as a TimeSpan"))
    
    secs = String(matched[7])
    if contains(secs, ".")
       secs, nanos = String.(split(secs, '.'))
    else
       nanos = ""
    end
    nanos = string(nanos, ZEROCHARS[10-length(nanos)])
    
    sgn = matched[1] == "-"
    
    yrs = Years(parse(Int, matched[2]))
    mos = Months(parse(Int, matched[3]))
    dys = Days(parse(Int, matched[4]))
    hrs = Hours(parse(Int, matched[5]))
    mis = Minutes(parse(Int, matched[6]))
    scs = Seconds(parse(Int, secs))
    nss = Nanoseconds(parse(Int, nanos))
    
    mos = mos + yrs
    mos = sgn ? -mos : mos
    nss = nss + scs + mis + hrs + dys
    nss = sgn ? -nss : nss
    
    return TimeSpan(nss, mos)
end

function parse_hms(::Type{TimeSpan}, str::String)
    matched = match(TimeSpan_hms_regex, str)
    if matched == nothing
        matched = match(TimeSpan_hms_regex2, str)
    end
    matched == nothing && throw(ErrorException("Unable to parse $(str) as a TimeSpan"))
    
    secs = String(matched[4])
    if contains(secs, ".")
       secs, nanos = String.(split(secs, '.'))
    else
       nanos = ""
    end
    nanos = string(nanos, ZEROCHARS[10-length(nanos)])
       
    sgn = matched[1] == "-"
    
    hrs = Hours(parse(Int, matched[2]))
    mis = Minutes(parse(Int, matched[3]))
    scs = Seconds(parse(Int, secs))
    nss = Nanoseconds(parse(Int, nanos))
    
    nss = nss + scs + mis + hrs
    nss = sgn ? -nss : nss
    
    return TimeSpan(nss, Months(0))
end

function parse_ymd(::Type{TimeSpan}, str::String)
    matched = match(TimeSpan_ymd_regex, str)
    if matched == nothing
        matched = match(TimeSpan_ymd_regex2, str)
    end
    matched == nothing && throw(ErrorException("Unable to parse $(str) as a TimeSpan"))
    
    sgn = matched[1] == "-"
    
    yrs = Years(parse(Int, matched[2]))
    mos = Months(parse(Int, matched[3]))
    dys = Days(parse(Int, matched[4]))
    
    mos = mos + yrs
    mos = sgn ? -mos : mos
    nss = Nanoseconds(dys)
    nss = sgn ? -nss : nss
    
    return TimeSpan(nss, mos)
end
